#include <iostream>
#include <fstream>
#include <sstream>
#include <cstring>

#include "process.h"

using namespace std;

// Constructor for Process
Process::Process(int ipid, int ipriority, int istart_time, char icode_loc [256]) {
  // Initialize vars
  pid = ipid; // Process ID
  priority = ipriority;
  start_time = istart_time;
  //cout << "New Process @ tick " << start_time << endl;
  cycles_completed = 0;
  pc = 0; // Place counter
  vc = 0; // Variable counter
  state = STATE_READY;
  mode = MODE_NORMAL;
  strcpy (code_loc, icode_loc); // Name of file containing code

  // Open trace file
  f = NULL;
  f = fopen(code_loc, "r");

  if (f == NULL) {
    cout << "ERROR: File not found: " << code_loc << endl;
    exit(1);
  }

  // Status report
  //  cout << "Started Process|pid:" << pid << "|File:" << icode_loc << "|Pri:" << priority << endl;
}

ProcessReturn Process::run() {
  // Allocate memory to hold a line from trace
  char line[256];
  if (line == NULL) {
    cout << "Out of memory" << endl;
    exit(1);
  }

  char* temp1;
  char* temp2;

  // Default return as RET_ERROR
  ProcessReturn pr;
  pr.ret = RET_ERROR;

  fgets (line, 256, f);

  // Which command -> Exec command
  stringstream ss(line);
  string s1, s2, s3;
  int val;

  // Switch on first character
  switch (line[0]) {
  case 'S': // Store x to VC
    ss >> s1 >> val;
    vc = val;

    cout << "Executing " << s1 << " " << val << " for PID = " << pid << endl;
    //    cout << "Found S, set VC as " << val << endl;
    pr.ret = RET_SUCCESS;
    break;

  case 'A': // Add x to VC
    ss >> s1 >> val;
    vc = vc + val;

    cout << "Executing " << s1 << " " << val << " for PID = " << pid << endl;
    //    cout << "Found A, added " << val << " to VC" << endl;
    pr.ret = RET_SUCCESS;
    break;

  case 'D': // Decrement x from VC
    ss >> s1 >> val;
    vc = vc - val;

    cout << "Executing " << s1 << " " << val << " for PID = " << pid << endl;
    //    cout << "Found D, decremented VC by " << val << endl;
    pr.ret = RET_SUCCESS;
    break;

  case 'C': // Create process (priority file-name)
    ss >> s1 >> val >> s2;

    pr.vals.newProcess.priority = val;

    temp1 = &s2[0];
    strcpy(pr.vals.newProcess.file_name, temp1);

    cout << "Executing " << s1 << ' ' << val << ' ' << s2 << " for PID = " << pid << endl;
    //    cout << "Found C, new process " << s2 << " " << val << endl;
    pr.ret = RET_NEW_PROCESS;
    break;

  case 'E': // Terminate current process
    cout << "Executing E for PID = " << pid << endl;
    //    cout << "Found E, Terminating process" << endl;
    pr.ret = RET_TERMINATED;
    break;

  case 'I': // IO syscall reqto given device (devclass B/C)
    ss >> s1 >> s2;

    temp1 = &s2[0];

    strcpy(pr.vals.bc, temp1);

    cout << "Executing " << s1 << ' ' << s2 << " for PID = " << pid << endl;
    //    cout << "Found I, Syscall to " << temp1 << " " << endl;
    pr.ret = RET_SYSCALL;
    break;

  case 'P': // Privileged instruction
    cout << "Executing P for PID = " << pid << endl;

    if (mode != MODE_PRIVILEGED) {
      pr.ret = RET_TERMINATED;

    } else { // mode == MODE_PRIVILEGED
      pr.ret = RET_SUCCESS;
    }
    break;

  default:
    cout << "Error: Unrecognized command: " << line[0] << endl;
    pr.ret = RET_ERROR;
  }

  // Cleanup
  pc++;
  cycles_completed++;

  pr.start_time = start_time;
  pr.cycles_completed = cycles_completed;

  return pr;
}

// Clean up after Process
void Process::close() {
  fclose(f);
}

